# （1）我是quant林，早年供职于上海的量化私募，后于2017年推出的免费Python期货CTP接口开源框架，采用GPLV3开源协议，简单易学，
# 适合学习入门和拓展开发，就在1.0版发布后不久，我的vnapi 1.0（当时不叫vnapi）就遭受了非法金融经营者用1.2万字连载诽谤文的诋毁攻击，
# 他们甚至在诽谤文下方还放上他们自己的涉及非法金融开源软件的广告。
# 从那次诋毁到现在2.10版的重新推出已过了快7年，人生又有几个7年？
# 当初我作为技术创业者从未遇到类似的情况，不知如何应对，2017年7月我离开上海去了重庆，在重庆
# 写出了virtualapi仿真回测（盛立版、CTP版、通联沪深A股Level2版）、vntrader6框架雏形、kucps专业投资软件的代码，
# 每天开发工作完毕，就去万州的小巷点一份小火锅和啤酒，这是我最难忘的回忆，2019年我又回到了上海，
# 在最近刀郎事件发生后，我开始怀疑我当初离开上海的想法和刀郎的想法是一样的。
# 由于非法金融具有伪装性和渗透性，前几年利用开源开源旗号不断侵蚀我国合规金融市场，某币圈网红公开宣传非法金融，
# 其带有非法金融交易功能的软件甚至短暂的上了某期货公司官网，后他们又于2021年11月被上海证监局调查。
# 在过去7年中，我在打击非法金融的战线上贡献了自己的力量，付出了大量时间和精力的代价，说不清楚这样做是为了自救，
# 还是别的原因，但我忠心的希望金融从业者们牢记合规底线，勿给非法金融可乘之机。
# 为记住那段历史，本次发布的vnapi2.10 期货CTP接口底层代码，正是源于2017年4月的1.0开源版本的稍作整理，已升级到最新的CTP版本，
# 1.0版就是被诋毁造谣的那个版本，vnapi改名前的1.0 版本曾被北京大学出版社《python3.x全栈开发》收录并重点介绍，
# 现在vnapi2.0作为一款Python CTP接口的框架，和当初1.0一样，是基于Ctypes技术，简单易学，主要目的是为了为开发者
# 提供一个通俗易懂的python后端开源框架，并非为了提供一款面面俱到的商业产品，适合入门学习和在此基础上继续拓展开发。
# 我还采用PyQt技术开发为前端开发的 vntrader6客户端（https://www.vnpy.cn）， 基于我开发的vnapi的另一个回调版本，
# 面向的是专业机构客户，VNTrader系列可以说在vnapi 1.0后端框架技术上迭代产生的，
# 当初的1.0，和今天发布的2.0，以及VNTrader、Virtualapi产品均属于我和上海量贝软件的原创产品，
# 我于2014年还获得基于AR增强现实技术的国家发明专利一项。
# 我另有正在申请3项量化交易发明专利，这些技术已授予用于上海量贝作为技术积累可用于商业技术开发。
# 也希望谣言发布者们知晓，靠谣言诋毁一个执迷于技术的程序员和技术创业者是不可能成功的。
# 承载着7年的维权经历与梦想，引来了vnapi2.10版本的发布，这个产品定位是作抛砖引玉之用，适合用户学习Python量化和扩展功能，
# 而非堆砌功能，请各位以宽容的眼光去对待他。
# （2）vnapi 遵循 开源协议GPL v3
# 简单得说：对基于GPL v3协议的源代码，若个人或机构仅仅是自己使用，则可以闭源。
# 若基于该开源代码，开发出程序或衍生产品用于商业行为则也需开源。
# 官方网站：http://www.vnpy.cn

# -*- coding=utf-8 -*-
import ctypes
from vnapictpmdType import *
import os, time


class vnapictpmd(object):
    def __init__(self):
        currpath = os.path.abspath(os.path.dirname(__file__))
        print(currpath)
        self.vnmd = ctypes.CDLL(currpath + '\\vnapictpmd.dll')
        '''
        i = 0
        while (i < 15):
            time.sleep(1)
            if (self.vnmd.IsInitOK() == 0):
                i += 1
            else:
                break
        else:
            print('market init error')
            return
        
        '''

        self.fReqUserLogin = self.vnmd.ReqUserLogin
        self.fReqUserLogin.argtypes = []
        self.fReqUserLogin.restype = c_int32

        self.fReqUserLogout = self.vnmd.ReqUserLogout
        self.fReqUserLogout.argtypes = []
        self.fReqUserLogout.restype = c_int32

        # self.fUnSubscribeMarketData = self.vnmd.UnSubscribeMarketData
        # self.fUnSubscribeMarketData.argtypes = [c_char_p]

        self.fOnCmd = self.vnmd.OnCmd
        self.fOnCmd.argtypes = []
        self.fOnCmd.restype = c_int32

        self.fGetCmdContent_Tick = self.vnmd.GetCmdContent_Tick
        self.fGetCmdContent_Tick.argtypes = []
        self.fGetCmdContent_Tick.restype = c_char_p

        self.fGetCmdContent_SubMarketData = self.vnmd.GetCmdContent_SubMarketData
        self.fGetCmdContent_SubMarketData.argtypes = []
        self.fGetCmdContent_SubMarketData.restype = c_void_p

        self.fGetCmdContent_UnSubMarketData = self.vnmd.GetCmdContent_UnSubMarketData
        self.fGetCmdContent_UnSubMarketData.argtypes = []
        self.fGetCmdContent_UnSubMarketData.restype = c_void_p

        self.fGetCmdContent_Forquote = self.vnmd.GetCmdContent_Forquote
        self.fGetCmdContent_Forquote.argtypes = []
        self.fGetCmdContent_Forquote.restype = c_void_p

        self.fGetCmdContent_Error = self.vnmd.GetCmdContent_Error
        self.fGetCmdContent_Error.argtypes = []
        self.fGetCmdContent_Error.restype = c_void_p

        self.fGetCmdContent_LoginScuess = self.vnmd.GetCmdContent_LoginScuess
        self.fGetCmdContent_LoginScuess.argtypes = []
        self.fGetCmdContent_LoginScuess.restype = c_void_p

        self.fGetCmdContent_LoginFailer = self.vnmd.GetCmdContent_LoginFailer
        self.fGetCmdContent_LoginFailer.argtypes = []
        self.fGetCmdContent_LoginFailer.restype = c_void_p

        self.fGetCmdContent_LoginOut = self.vnmd.GetCmdContent_LoginOut
        self.fGetCmdContent_LoginOut.argtypes = []
        self.fGetCmdContent_LoginOut.restype = c_void_p

        self.fGetCmd = self.vnmd.GetCmd
        self.fGetCmd.argtypes = []
        self.fGetCmd.restype = c_int32

        self.fGetCmdContent = self.vnmd.GetCmdContent
        self.fGetCmdContent.argtypes = []
        self.fGetCmdContent.restype = c_char_p

        self.fGetUnGetCmdSize = self.vnmd.GetUnGetCmdSize
        self.fGetUnGetCmdSize.argtypes = []
        self.fGetUnGetCmdSize.restype = c_int32

        self.fGetApiVersion = self.vnmd.GetApiVersion
        self.fGetApiVersion.argtypes = []
        self.fGetApiVersion.restype = c_char_p

        self.fGetTradingDay = self.vnmd.GetTradingDay
        self.fGetTradingDay.argtypes = []
        self.fGetTradingDay.restype = c_char_p

        self.fRegisterFront = self.vnmd.RegisterFront
        self.fRegisterFront.argtypes = [c_char_p]

        self.fRegisterNameServer = self.vnmd.RegisterNameServer
        self.fRegisterNameServer.argtypes = [c_char_p]

        self.fGetData = self.vnmd.GetData
        self.fGetData.argtypes = [c_int32]
        self.fGetData.restype = c_void_p

        self.fSubscribeMarketData = self.vnmd.SubscribeMarketData
        self.fSubscribeMarketData.argtypes = [c_char_p]
        self.fSubscribeMarketData.restype = c_int32

        self.fSubscribeForQuoteRsp = self.vnmd.SubscribeForQuoteRsp
        self.fSubscribeForQuoteRsp.argtypes = [c_char_p]

        self.InstrumentNum = self.vnmd.GetInstrumentNum()

        self.fGetPeriodData = self.vnmd.GetPeriodData
        self.fGetPeriodData.argtypes = [c_char_p, c_int32, c_int32, c_int32]
        self.fGetPeriodData.restype = c_double

        self.fSaveTick = self.vnmd.SaveTick
        self.fSaveTick.argtypes = [c_int32]
        self.fSaveTick.restype = c_void_p

        self.fLog = self.vnmd.Log
        self.fLog.argtypes = [c_char_p, c_char_p]
        self.fLog.restype = c_void_p

        self.fSetRejectdataTime = self.vnmd.SetRejectdataTime
        self.fSetRejectdataTime.argtypes = [c_double, c_double, c_double, c_double, c_double, c_double, c_double,
                                            c_double]
        self.fSetRejectdataTime.restype = c_void_p

        self.Index = dict()
        for i in range(self.InstrumentNum):
            data = self.fGetData(i)
            data = cast(data, POINTER(sDepMarketData))
            self.Index[str(data[0].InstrumentID)] = data
        pass

    def TradingDay(self, InstrumentID):
        # 交易日
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].TradingDay
        else:
            return ''

    def InstrumentID(self, InstrumentID):
        # 合约代码
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].InstrumentID
        else:
            return ''

    def ExchangeID(self, InstrumentID):
        # 交易所代码
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].ExchangeID
        else:
            return ''

    def ExchangeInstID(self, InstrumentID):
        # 合约在交易所的代码
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].ExchangeInstID
        else:
            return ''

    def LastPrice(self, InstrumentID):
        # 最新价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].LastPrice, 1)
        else:
            return -1

    def PreSettlementPrice(self, InstrumentID):
        # 上次结算价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].PreSettlementPrice, 1)
        else:
            return -1

    def PreClosePrice(self, InstrumentID):
        # 昨收盘
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].PreClosePrice, 1)
        else:
            return -1

    def PreOpenInterest(self, InstrumentID):
        # 昨持仓量
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].PreOpenInterest
        else:
            return -1

    def OpenPrice(self, InstrumentID):
        # 今开盘
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].OpenPrice, 1)
        else:
            return -1

    def HighestPrice(self, InstrumentID):
        # 最高价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].HighestPrice, 1)
        else:
            return -1

    def LowestPrice(self, InstrumentID):
        # 最低价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].LowestPrice, 1)
        else:
            return -1

    def Volume(self, InstrumentID):
        # 数量
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].Volume
        else:
            return -1

    def Turnover(self, InstrumentID):
        # 成交金额
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].Turnover
        else:
            return -1

    def OpenInterest(self, InstrumentID):
        # 持仓量
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].OpenInterest
        else:
            return -1

    def ClosePrice(self, InstrumentID):
        # 今收盘
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].ClosePrice, 1)
        else:
            return -1

    def SettlementPrice(self, InstrumentID):
        # 本次结算价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].SettlementPrice, 1)
        else:
            return -1

    def UpperLimitPrice(self, InstrumentID):
        # 涨停板价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].UpperLimitPrice, 1)
        else:
            return -1

    def LowerLimitPrice(self, InstrumentID):
        # 跌停板价
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].LowerLimitPrice, 1)
        else:
            return -1

    def PreDelta(self, InstrumentID):
        # 昨虚实度
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].PreDelta
        else:
            return -1

    def CurrDelta(self, InstrumentID):
        # 今虚实度
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].CurrDelta
        else:
            return -1

    def UpdateTime(self, InstrumentID):
        # 最后修改时间
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].UpdateTime
        else:
            return ''

    def UpdateMillisec(self, InstrumentID):
        # 最后修改毫秒
        if InstrumentID in self.Index:
            return self.Index[InstrumentID][0].UpdateMillisec
        else:
            return 0

    def BidPrice1(self, InstrumentID):
        # 申买价一
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidPrice1, 1)
        else:
            return -1

    def BidVolume1(self, InstrumentID):
        # 申买量一
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidVolume1, 1)
        else:
            return -1

    def AskPrice1(self, InstrumentID):
        # 申卖价一
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskPrice1, 1)
        else:
            return -1

    def AskVolume1(self, InstrumentID):
        # 申卖量一
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskVolume1, 1)
        else:
            return -1

    def BidPrice2(self, InstrumentID):
        # 申买价二
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidPrice2, 1)
        else:
            return -1

    def BidVolume2(self, InstrumentID):
        # 申买量二
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidVolume2, 1)
        else:
            return None

    def AskPrice2(self, InstrumentID):
        # 申卖价二
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskPrice2, 1)
        else:
            return None

    def AskVolume2(self, InstrumentID):
        # 申卖量二
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskVolume2, 1)
        else:
            return None

    def BidPrice3(self, InstrumentID):
        # 申买价三
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidPrice3, 1)
        else:
            return None

    def BidVolume3(self, InstrumentID):
        # 申买量三
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidVolume3, 1)
        else:
            return None

    def AskPrice3(self, InstrumentID):
        # 申卖价三
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskPrice3, 1)
        else:
            return None

    def AskVolume3(self, InstrumentID):
        # 申卖量三
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskVolume3, 1)
        else:
            return None

    def BidPrice4(self, InstrumentID):
        # 申买价四
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidPrice4, 1)
        else:
            return None

    def BidVolume4(self, InstrumentID):
        # 申买量四
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidVolume4, 1)
        else:
            return None

    def AskPrice4(self, InstrumentID):
        # 申卖价四
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskPrice4, 1)
        else:
            return None

    def AskVolume4(self, InstrumentID):
        # 申卖量四
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskVolume4, 1)
        else:
            return None

    def BidPrice5(self, InstrumentID):
        # 申买价五
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidPrice5, 1)
        else:
            return None

    def BidVolume5(self, InstrumentID):
        # 申买量五
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].BidVolume5, 1)
        else:
            return None

    def AskPrice5(self, InstrumentID):
        # 申卖价五
        if InstrumentID in self.Index:
            return round(self.Index[InstrumentID][0].AskPrice5, 1)
        else:
            return None

    def AskVolume5(self, InstrumentID):
        # 申卖量五
        if contract in self.Index:
            return (self.Index[InstrumentID][0].AskVolume5, 1)
        else:
            return None

    def AveragePrice(self, InstrumentID):
        # 当日均价
        if contract in self.Index:
            return round(self.Index[InstrumentID][0].AveragePrice, 1)
        else:
            return None

    # 订阅询价
    def SubscribeForQuoteRsp(self, InstrumentID):
        # 订阅合约时，请注意合约的大小写，中金所和郑州交易所是大写，上海和大连期货交易所是小写的
        self.fSubscribeForQuoteRsp(bytes(InstrumentID, encoding="utf-8"))

    # data = self.fGetData(len(self.Index))
    # data = cast(data, POINTER(sDepMarketData))
    # self.Index[contract] = data
    def SubscribeMarketData(self, InstrumentID):
        self.fSubscribeMarketData(bytes(InstrumentID, encoding="utf-8"))
        # data = self.fGetData(len(self.Index))
        # data =  POINTER(sDepMarketData)
        # self.Index[contract] = data

    # def AddPeriod(self, contract, periodtype):
    # 订阅合约时，请注意合约的大小写，中金所和郑州交易所是大写，上海和大连期货交易所是小写的
    #    self.fAddPeriod(contract, periodtype, True)

    # data = self.fGetData(len(self.Index))
    # data = cast(data, POINTER(sDepMarketData))
    # self.Index[contract] = data

    # def AddPeriod(self, contract):
    # MA测试
    # self.fAddPeriod(c_char_p(contract))

    def GetPeriodData(self, instrumentID, periodtype, pricetype, ref):
        return self.fGetPeriodData(bytes(instrumentID, encoding="gb2312"), periodtype, pricetype, ref)

    def SaveTick(self, index):
        self.fSaveTick(index)

    def Log(self, instrumentID):
        return self.fLog(bytes(instrumentID, encoding="gb2312"))

    # def SetRejectdataTime(self, begintime1, endtime1, begintime2, endtime2, begintime3, endtime3, begintime4, endtime4):
    #    return self.fSetRejectdataTime(begintime1, endtime1, begintime2, endtime2, begintime3, endtime3, begintime4,
    #                                   endtime4)

    def ReqUserLogin(self):
        return self.fReqUserLogin()

    def ReqUserLogout(self):
        return self.fReqUserLogout()

    # def UnSubscribeMarketData(self, contract):
    #    return self.fUnSubscribeMarketData(contract)

    def OnCmd(self):
        return self.fOnCmd()

    def GetCmd(self):
        # fGetCmd(), fGetCmdContent()必须配对同时使用
        return (self.fGetCmd(), self.fGetCmdContent())

    def GetUnGetCmdSize(self):
        return self.fGetUnGetCmdSize()

    def RegisterFront(self, pszFrontAddress):
        self.fRegisterFront(bytes(pszFrontAddress, encoding="gb2312"))

    def RegisterNameServer(self, pszNsAddress):
        self.fRegisterNameServer(bytes(pszNsAddress, encoding="gb2312"))

    def GetCmdContent_Tick(self):
        # 错误信息回调
        return self.fGetCmdContent_Tick()

    def GetCmdContent_SubMarketData(self):
        # 错误信息回调
        return self.fGetCmdContent_SubMarketData()

    def GetCmdContent_UnSubMarketData(self):
        # 错误信息回调
        return self.fGetCmdContent_UnSubMarketData()

    def GetCmdContent_Forquote(self):
        # 错误信息回调
        return self.fGetCmdContent_Forquote()

    def GetCmdContent_Error(self):
        # 错误信息回调
        return self.fGetCmdContent_Error()

    def GetCmdContent_LoginScuess(self):
        # 错误信息回调
        return self.fGetCmdContent_LoginScuess()

    def GetCmdContent_LoginFailer(self):
        # 错误信息回调
        return self.fGetCmdContent_LoginFailer()

    def GetCmdContent_LoginOut(self):
        # 错误信息回调
        return self.fGetCmdContent_LoginOut()
